package com.qianyucc.blog.service;

import cn.hutool.core.bean.*;
import cn.hutool.core.bean.copier.*;
import cn.hutool.core.date.*;
import cn.hutool.core.util.*;
import com.google.common.base.*;
import com.qianyucc.blog.exception.*;
import com.qianyucc.blog.mapper.*;
import com.qianyucc.blog.model.dto.*;
import com.qianyucc.blog.model.entity.*;
import com.qianyucc.blog.model.enums.*;
import com.qianyucc.blog.model.pojo.*;
import com.qianyucc.blog.model.vo.*;
import com.qianyucc.blog.utils.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.*;

import java.time.*;
import java.util.Optional;
import java.util.*;
import java.util.stream.*;

import static com.qianyucc.blog.global.Constants.*;

/**
 * @author lijing
 * @date 2019-10-12 14:33
 * @description 与文章相关的业务
 */
@Service
public class ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private CommentService commentService;
    @Autowired
    private DraftMapper draftMapper;
    @Autowired
    private Configs configs;

    /**
     * 根据id查询文章信息
     *
     * @param id 文章id
     * @return 要展示到前端的文章信息
     */
    public ArticleVO findArticleById(String id) {
        ArticleDO articleDO = articleMapper.findById(id);
        if (articleDO != null) {
            ArticleVO articleVO = ArticleVO.create(articleDO);
            //增加阅读数
            articleMapper.updateViews(id);
            return articleVO;
        } else {
            throw new NotFindArticleException(StrUtil.format("找不到id为{}的文章！", id));
        }
    }


    /**
     * 获取所有标签
     *
     * @return 所有标签的列表
     */
    public Set<String> findAllTags() {
        // 使用Set去重
        List<String> allTags = articleMapper.findAllTags();
        Set<String> resList = new HashSet<>();
        allTags.forEach(tag -> Collections.addAll(resList, Optional.ofNullable(tag)
                .map(t -> t.split(","))
                .orElse(new String[0])));
        return resList;
    }


    /**
     * 获取所有的月份
     *
     * @return 月份列表
     */
    public Set<String> archivesMonths() {
        Set<String> res = new TreeSet<>((o1, o2) -> -o1.compareTo(o2));
        List<Long> allGmtCreate = articleMapper.findAllGmtCreates();
        allGmtCreate.forEach(gmtUpdate -> res.add(Utils.formatDate(gmtUpdate, "yyyy年MM月")));
        return res;
    }

    /**
     * 插入文章
     *
     * @param articleDTO 要插入的文章
     */
    @Transactional(rollbackFor = Exception.class)
    public void insArticle(ArticleDTO articleDTO) {
        ArticleDO articleDO = new ArticleDO();
        // 删除草稿
        if (articleDTO.getDraftId() != null) {
            draftMapper.deleteById(articleDTO.getDraftId());
        }
        // type==1说明为原创
        if (articleDTO.getType() == ArticleType.ORIGINAL.getFlag()) {
            articleDO.setAuthor(configs.getPenName());
        }
        BeanUtil.copyProperties(articleDTO, articleDO, new CopyOptions().ignoreNullValue().ignoreError());
        articleDO.setViews(0);
        articleDO.setTags(ArrayUtil.join(articleDTO.getTags(), ","));
        articleDO.setId(IdUtil.objectId());
        articleDO.setGmtCreate(Instant.now().toEpochMilli());
        articleDO.setGmtUpdate(articleDO.getGmtCreate());
        articleMapper.insArticle(articleDO);
    }

    /**
     * 更新文章
     *
     * @param articleDTO 要更新的文章
     */
    @Transactional(rollbackFor = Exception.class)
    public void updArticle(ArticleDTO articleDTO) {
        ArticleDO articleDO = articleMapper.findById(articleDTO.getId());
        // 删除草稿
        if (articleDTO.getDraftId() != null) {
            draftMapper.deleteById(articleDTO.getDraftId());
        }
        // type==1说明为原创
        if (articleDTO.getType() == ArticleType.ORIGINAL.getFlag()) {
            articleDO.setAuthor(configs.getPenName());
        }
        BeanUtil.copyProperties(articleDTO, articleDO, new CopyOptions().ignoreNullValue());
        String[] tags = articleDTO.getTags();
        if (tags != null && tags.length > 0) {
            articleDO.setTags(ArrayUtil.join(tags, ","));
        }
        articleDO.setGmtUpdate(Instant.now().toEpochMilli());
        articleMapper.updArticle(articleDO);
    }

    /**
     * 根据前端传来的条件查询（对应管理员的搜索功能）
     *
     * @param qcDTO 查询条件
     * @return 查询到的数据
     */
    public PageInfoVO<SimpleArticleVO> findArticles(QueryConditionDTO qcDTO) {
        Map<String, Object> QUERY_MAP = queryMap();
        String regex = null;
        if (qcDTO.getPageNumber() > 1) {
            QUERY_MAP.put("offset", (qcDTO.getPageNumber() - 1) * DEFAULT_PAGE_SIZE);
        }

        if (!Strings.isNullOrEmpty(qcDTO.getKeywords())) {
            regex = Joiner.on('|').join(Utils.splitKeywords(qcDTO.getKeywords()));
            QUERY_MAP.put("title", ".*(" + regex + ").*");
        }
        if (!Strings.isNullOrEmpty(qcDTO.getTag())) {
            QUERY_MAP.put("tag", qcDTO.getTag());
        }
        if (!Strings.isNullOrEmpty(qcDTO.getCategory())) {
            QUERY_MAP.put("category", qcDTO.getCategory());
        }
        if (!Strings.isNullOrEmpty(qcDTO.getDate())) {
            DateTime dateTime = DateUtil.parse(qcDTO.getDate(), "yyyy-MM-dd");
            Long currentday = dateTime.getTime();
            Long nextday = dateTime.offset(DateField.DAY_OF_YEAR, 1).getTime();
            QUERY_MAP.put("day", currentday);
            QUERY_MAP.put("nextDay", nextday);
        }
        List<ArticleDO> articleDOS = articleMapper.findByCondition(QUERY_MAP);
        Long count = articleMapper.countByCondition(QUERY_MAP);
        List<SimpleArticleVO> articleVOS = articleDOS
                .stream()
                .map(SimpleArticleVO::create)
                .collect(Collectors.toList());
        int totalPages = (int) (count % DEFAULT_PAGE_SIZE == 0 ?
                count / DEFAULT_PAGE_SIZE : count / DEFAULT_PAGE_SIZE + 1);
        return PageInfoVO.create(qcDTO.getPageNumber(), totalPages, count, articleVOS);
    }

    /**
     * 根据id删除文章
     *
     * @param id 要删除的文章id
     */
    public void delete(String id) {
        articleMapper.deleteArticle(id);
        // 删除文章下所有评论
        HashMap<String, Object> map = new HashMap<>();
        map.put("parentId", id);
        map.put("type", 1);
        List<CommentDO> commentDOS = commentMapper.findByArticleId(id);
        for (CommentDO commentDO : commentDOS) {
            commentMapper.deleteById(commentDO.getId());
        }
    }

    /**
     * 根据不同条件，分页查询文章（对应普通用户的搜索功能）
     *
     * @param pageNumber 页码
     * @param condition  查询条件
     * @param data       查询条件对应的数据
     * @return 符合条件的一页数据
     */
    public PageInfoVO<SimpleArticleVO> findByCondition(Integer pageNumber, Integer pageSize, String condition, String data) {
        Map<String, Object> QUERY_MAP = queryMap();
        String regex = null;
        if (!Strings.isNullOrEmpty(condition) && Strings.isNullOrEmpty(data)) {
            // 请完整填写数据
            throw new IncompleteInfoException();
        }
        if (pageNumber > 1) {
            QUERY_MAP.put("offset", (pageNumber - 1) * pageSize);
        }
        if ("tag".equals(condition)) {
            QUERY_MAP.put("tag", "%" + data + "%");
        } else if ("category".equals(condition)) {
            QUERY_MAP.put("category", data);
        } else if ("str".equals(condition)) {
            regex = Joiner.on('|').join(Utils.splitKeywords(data));
            QUERY_MAP.put("title", ".*(" + regex + ").*");
        } else if ("month".equals(condition)) {
            Set<String> months = archivesMonths();
            if (months.size() > 0) {
                DateTime currentMonth = DateUtil.parse(data, "yyyy年MM月");
                //设置为不可变对象后变动将返回新对象，此时nextMonth != currentMonth
                currentMonth.setMutable(false);
                DateTime nextMonth = currentMonth.offset(DateField.MONTH, 1);
                QUERY_MAP.put("month", currentMonth.getTime());
                QUERY_MAP.put("nextMonth", nextMonth.getTime());
            }
        }
        List<ArticleDO> articleDOS = articleMapper.findByCondition(QUERY_MAP);
        Long count = articleMapper.countByCondition(QUERY_MAP);
        List<SimpleArticleVO> articleVOS = articleDOS.stream().map(SimpleArticleVO::create).collect(Collectors.toList());
        if ("str".equals(condition)) {
            // 将标题中关键字替换为红色
            for (SimpleArticleVO articleVO : articleVOS) {
                String title = articleVO.getTitle();
                // 利用正则替换
                String newTitle = title.replaceAll(regex, CSS_FONT_RED);
                articleVO.setTitle(newTitle);
            }
        }
        int totalPages = (int) (count % pageSize == 0 ? count / pageSize : count / pageSize + 1);
        return PageInfoVO.create(pageNumber, totalPages, count, articleVOS);
    }
}
